from collections import namedtuple

### TOKENS ###
t_TOKEN001 = r'[0-9]+'
t_TOKEN002 = r'\('
t_TOKEN003 = r'\)'
t_TOKEN004 = r'\*'
t_TOKEN005 = r'\+'
t_TOKEN006 = r'-'
t_TOKEN007 = r'true'
t_TOKEN008 = r'false'
t_TOKEN009 = r'='
t_TOKEN010 = r'<='
t_TOKEN011 = r'!'
t_TOKEN012 = r'&'
t_TOKEN013 = r';'
t_TOKEN014 = r'[a-zA-Z]\w*'
t_TOKEN015 = r':='
t_TOKEN016 = r'skip'
t_TOKEN017 = r'if'
t_TOKEN018 = r'then'
t_TOKEN019 = r'else'
t_TOKEN020 = r'while'
t_TOKEN021 = r'do'
t_TOKEN022 = r'\{'
t_TOKEN023 = r'\}'

### PRECEDENCE ###
precedence = (

    )

### RULES ###
def __concat__(x,y):
	return (x if type( x ) is list else [x]) + (y if type( y ) is list else [y])

def p_RULE001(p): # aexp : /[0-9]+/ > (Numeral n:$1)
	"aexp : TOKEN001"
	p[0] = Numeral(n=p[1])

def p_RULE002(p): # aexp : '(' aexp ')' > $2
	"aexp : TOKEN002 aexp TOKEN003"
	p[0] = p[2]

def p_RULE003(p): # aexp : aexp '*' aexp > (Multiplication a1:$1 a2:$3)
	"aexp : aexp TOKEN004 aexp"
	p[0] = Multiplication(a1=p[1], a2=p[3])

def p_RULE004(p): # aexp : aexp '+' aexp > (Addition a1:$1 a2:$3)
	"aexp : aexp TOKEN005 aexp"
	p[0] = Addition(a1=p[1], a2=p[3])

def p_RULE005(p): # aexp : aexp '-' aexp > (Subtraction a1:$1 a2:$3)
	"aexp : aexp TOKEN006 aexp"
	p[0] = Subtraction(a1=p[1], a2=p[3])

def p_RULE006(p): # bexp : 'true' > (LiteralTrue)
	"bexp : TOKEN007"
	p[0] = LiteralTrue()

def p_RULE007(p): # bexp : 'false' > (LiteralFalse)
	"bexp : TOKEN008"
	p[0] = LiteralFalse()

def p_RULE008(p): # bexp : '(' bexp ')' > $2
	"bexp : TOKEN002 bexp TOKEN003"
	p[0] = p[2]

def p_RULE009(p): # bexp : aexp '=' aexp > (Equals a1:$1 a2:$3)
	"bexp : aexp TOKEN009 aexp"
	p[0] = Equals(a1=p[1], a2=p[3])

def p_RULE010(p): # bexp : aexp '<=' aexp > (LessThanOrEqual a1:$1 a2:$3)
	"bexp : aexp TOKEN010 aexp"
	p[0] = LessThanOrEqual(a1=p[1], a2=p[3])

def p_RULE011(p): # bexp : '!' bexp > (Negation b:$2)
	"bexp : TOKEN011 bexp"
	p[0] = Negation(b=p[2])

def p_RULE012(p): # bexp : bexp '&' bexp > (Conjuntion b1:$1 b2:$3)
	"bexp : bexp TOKEN012 bexp"
	p[0] = Conjuntion(b1=p[1], b2=p[3])

def p_RULE013(p): # main : seq > (Sequence stmts:$1)
	"main : seq"
	p[0] = Sequence(stmts=p[1])

def p_RULE014(p): # seq : stmt > [$1]
	"seq : stmt"
	p[0] = [p[1]]

def p_RULE015(p): # seq : seq ';' stmt > $1:$3
	"seq : seq TOKEN013 stmt"
	p[0] = __concat__(p[1], p[3])

def p_RULE016(p): # stmt : /[a-zA-Z]\w*/ ':=' aexp > (Assignment x:$1 a:$2)
	"stmt : TOKEN014 TOKEN015 aexp"
	p[0] = Assignment(x=p[1], a=p[2])

def p_RULE017(p): # stmt : 'skip' > (Skip)
	"stmt : TOKEN016"
	p[0] = Skip()

def p_RULE018(p): # stmt : 'if' bexp 'then' stmt 'else' stmt > (IfThenElse b:$2 s1:$4 s2:$6)
	"stmt : TOKEN017 bexp TOKEN018 stmt TOKEN019 stmt"
	p[0] = IfThenElse(b=p[2], s1=p[4], s2=p[6])

def p_RULE019(p): # stmt : 'while' bexp 'do' stmt > (WhileDo b:$2 s:$4)
	"stmt : TOKEN020 bexp TOKEN021 stmt"
	p[0] = WhileDo(b=p[2], s=p[4])

def p_RULE020(p): # stmt : '{' seq '}' > (Sequence stmts:$2)
	"stmt : TOKEN022 seq TOKEN023"
	p[0] = Sequence(stmts=p[2])


### AST ###
class ArithmeticExpression:
	pass

class Numeral(namedtuple('Numeral', 'n'), ArithmeticExpression):
	pass

class Multiplication(namedtuple('Multiplication', 'a1 a2'), ArithmeticExpression):
	pass

class Addition(namedtuple('Addition', 'a1 a2'), ArithmeticExpression):
	pass

class Subtraction(namedtuple('Subtraction', 'a1 a2'), ArithmeticExpression):
	pass

class BooleanExpression:
	pass

class LiteralTrue(namedtuple('LiteralTrue'), BooleanExpression):
	pass

class LiteralFalse(namedtuple('LiteralFalse'), BooleanExpression):
	pass

class Equals(namedtuple('Equals', 'a1 a2'), BooleanExpression):
	pass

class LessThanOrEqual(namedtuple('LessThanOrEqual', 'a1 a2'), BooleanExpression):
	pass

class Negation(namedtuple('Negation', 'b'), BooleanExpression):
	pass

class Conjuntion(namedtuple('Conjuntion', 'b1 b2'), BooleanExpression):
	pass

class Statement:
	pass

class Sequence(namedtuple('Sequence', 'stmts'), Statement):
	pass

class Assignment(namedtuple('Assignment', 'x a'), Statement):
	pass

class Skip(namedtuple('Skip'), Statement):
	pass

class IfThenElse(namedtuple('IfThenElse', 'b s1 s2'), Statement):
	pass

class WhileDo(namedtuple('WhileDo', 'b s'), Statement):
	pass

